/*
1.unique_lock取代lockguard
uniquelock是一个类模板，工作中一般使用lockguard；
lockguard取代了mutex的lock（）和unlock（）
uniquelock比lockguard灵活，但是占用内存，效率低

2.uniquelock内部同样是在构造中lock在析构中unlock

3.uniquelock可以带第二个参数,比lockguard的参数选择多
	参数adoptlock，禁止锁定，前提是我们手动lock过
	参数trytolock，尝试锁定，前提是我们没有lock过，否则程序卡死
		trytolock尝试锁定，如果没有锁住也会返回，并不会阻塞在哪里
	参数deferlock，初始化了一个没有加锁的mutext，前提我们没有lock
		此时我们需要后续手动unlock


4.uniquelock的成员函数
	lock()
	unlock()
	可以利用uniquelock的对象进行加锁和解锁，进行临时操作
	trylock()尝试加锁

	以上成员函数和deferlock参数配合使用

	release（）解绑uniquelock和mutex，并返回mutex的对象指针
	此后我们要负责mutex的解锁


	锁住的代码越少，执行效率越高，锁住代码的多少被称为锁的粒度，一般用粗细来描述
	锁住的代码少，被称为细，执行效率高；反之为粗

5.所有权
	unique_lock<mutex> my_guard(my_mutex);即my-guard有my-mutex的所有权
	my-guard可以将自己的my-mutex的所有权转移给其他的uniquelock对象
	但是不可以复制
	例如：unique_lock<mutex> my_guard(my_mutex);
		unique_lock<mutex> my_guard2(my_guard);
		这样是非法的
		但是可以利用move成员函数实现
		unique_lock<mutex> my_guard(my_mutex);
		unique_lock<mutex> my_guard2(std::move(my_guard));
		(移动语义）

	转移所有权，可以在类内返回一个mutex对象




*/



#include<iostream>
#include<thread>
#include<vector>
#include <list>
#include<mutex>
using namespace std;

class A {
public:

	//5.
	//移动构造函数
	unique_lock<mutex> rtn_unique_lock() {
		//创建临时uniquelock对象
		unique_lock<mutex> temp_guard(my_mutex);
		//返回临时对象
		//从函数中返回一个局部变量是合法的
		//返回临时变量，会导致系统生成临时的uniquelock对象，并调用其移动构造函数
		//最终mymutex的所有权转移到调用这个函数的对象身上
		return temp_guard;
	}



	//线程入口，读入消息队列
	void inMsgRecvQueue() {
		for (int i = 0; i < 10000; ++i) {
			unique_lock<mutex> my_guard(my_mutex, try_to_lock);

			//此时所有权在my-guard2上
			unique_lock<mutex> my_guard2 = rtn_unique_lock();
			if (my_guard.owns_lock()) {
				//成员函数ownslock返回释放获得了锁
				//如果获得了
				cout << "插入元素" << i << endl;
				msgRecvQueue.push_back(i);
			}
			else
			{
				//如果没有获得,干别的事
				//此时程序不会停止
				cout << "没有拿到锁" << endl;
			}


		}
	}
	//共享数据操作，提取到一个方法中
	bool outMsgLULProc() {
		//语法与lockguard类似
		unique_lock<mutex>(my_mutex);

		std::chrono::milliseconds dura(2);//定义2秒
		this_thread::sleep_for(dura);//休息2秒
		//这导致输入数据也要等
		//这不是我们希望的,我们希望在这2秒中内，虽然不能输入数据，但是那个
		//方法可以做别的事情

		if (!msgRecvQueue.empty()) {
			//消息不为空
			cout << "读取元素" << msgRecvQueue.front() << endl;
			msgRecvQueue.pop_front();
			return true;
		}
		else {
			return false;
		}

	}

	//线程入口，取出消息队列
	void outMsgRecvQueue() {
		
		for (int i = 0; i < 100000; ++i) {
			if (outMsgLULProc()) {
				//具体操作
				cout << "具体操作";
			}
			else {
				cout << "消息为空" << i << endl;
			}
		}
		cout << "消息处理结束" << endl;
	}

private:
	list<int> msgRecvQueue;
	mutex my_mutex;

};


int main(int argc, char* argv[]) {

	A myobja;
	thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
	myOutMsgObj.join();
	myInMsgObj.join();

	return 0;
}